package com.oneday.ashop.console.base.shiro;

import com.oneday.ashop.console.authority.AuthDao;
import com.oneday.ashop.console.authority.AuthService;
import com.oneday.ashop.console.base.shiro.filter.BaseResourceFilter;
import com.oneday.ashop.core.entity.Admin;
import com.oneday.ashop.core.entity.Role;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Set;

/**
 * 自定义Realm,进行数据源配置
 * 
 * @author lanyuan 2014-12-25
 * @Email: mmm333zzz520@163.com
 * @version 3.0v
 */
@Slf4j
public class MyRealm extends AuthorizingRealm {

	@Autowired
	private AuthService authService;

	@Autowired
	private BaseResourceFilter baseResourceFilter;

	@Autowired
	private AuthDao authDao;

	/**
	 * 只有需要验证权限时才会调用, 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.在配有缓存的情况下，只加载一次.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
		//获得用户名
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		//查询该用户所有的角色信息(这里不能用用户在缓存中的角色信息)
		Admin admin = authDao.findAdminById(((Admin) SecurityUtils.getSubject().getPrincipal()).getId());
		List<Integer> roleIds = admin.getRoleIds();
		if(roleIds != null) {
			List<Role> roles = authService.findRoles(roleIds);
			for (Role role : roles) {
				info.addRole(role.getName());
			}
		}
		return info;
	}

	/**
	 * 认证回调函数,登录时调用
	 * 首先根据传入的用户名获取User信息；然后如果user为空，那么抛出没找到帐号异常UnknownAccountException；
	 * 如果user找到但锁定了抛出锁定异常LockedAccountException；最后生成AuthenticationInfo信息，
	 * 交给间接父类AuthenticatingRealm使用CredentialsMatcher进行判断密码是否匹配，
	 * 如果不匹配将抛出密码错误异常IncorrectCredentialsException；
	 * 另外如果密码重试此处太多将抛出超出重试次数异常ExcessiveAttemptsException；
	 * 在组装SimpleAuthenticationInfo信息时， 需要传入：身份信息（用户名）、凭据（密文密码）、盐（username+salt），
	 * CredentialsMatcher使用盐加密传入的明文密码和此处的密文密码进行匹配。
	 */
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//		if(BaseResourceFilter.resourceMap.isEmpty()) {
//			baseResourceFilter.init();
//		}


		String name = (String) token.getPrincipal();
		Admin admin = authDao.findAdmin(name);
		if (admin != null) {
			String password =  new SimpleHash("md5", admin.getPassword(), ByteSource.Util.bytes(name + "" +	admin.getPassword()), 2).toHex();
//			if ("2".equals(userFormMaps.get(0).get("locked"))) {
//				throw new LockedAccountException(); // 帐号锁定
//			}
			// 从数据库查询出来的账号名和密码,与用户输入的账号和密码对比
			// 当用户执行登录时,在方法处理上要实现user.login(token);
			// 然后会自动进入这个类进行认证
			// 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配，如果觉得人家的不好可以自定义实现
			SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(admin, // 用户名
					password, // 密码
					ByteSource.Util.bytes(name + "" + admin.getPassword()),// salt=username+salt
					getName() // realm name
			);
			// 当验证都通过后，把用户信息放在session里
//			doGetAuthorizationInfo(SecurityUtils.getSubject().getPreviousPrincipals());
			Session session = SecurityUtils.getSubject().getSession();
			session.setAttribute("userSession", admin);
			session.setAttribute("userSessionId", admin.getId());
			return authenticationInfo;
//			return null;
		} else {
			throw new UnknownAccountException();// 没找到帐号
		}

	}
	/**
     * 更新用户授权信息缓存.
     */
	public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
		super.clearCachedAuthorizationInfo(principals);
	}
	/**
     * 更新用户信息缓存.
     */
	public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
		super.clearCachedAuthenticationInfo(principals);
	}

	/**
	 * 清除用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo() {
		getAuthorizationCache().clear();
	}

	/**
	 * 清除用户信息缓存.
	 */
	public void clearAllCachedAuthenticationInfo() {
		getAuthenticationCache().clear();
	}
	
	/**
	 * 清空所有缓存
	 */
	public void clearCache(PrincipalCollection principals) {
		super.clearCache(principals);
	}


	/**
	 * 清空所有认证缓存
	 */
	public void clearAllCache() {
		clearAllCachedAuthenticationInfo();
		clearAllCachedAuthorizationInfo();
	}



}